package com.ies.dx.util;

import java.io.EOFException;

public class ByteArrayLittleEdianInput implements Input
{
    
    private byte[] mBytes;
    private int mCursor;
    
    public ByteArrayLittleEdianInput(byte[] bytes)
    {
        mBytes = bytes;
    }
    
    public int getCursor()
    {
        return mCursor;
    }
    
    public void moveCursorTo(int pos)
    {
        mCursor = pos;
    }

    public void assertCursor(int expectedCursor)
    {
        
    }

    public byte readByte() throws EOFException
    {        
        if (mCursor + 1 > mBytes.length)
            throw new EOFException();
        byte result = mBytes[mCursor];
        mCursor ++;
        return result;
    }
    
    public int readUnsignedByte()throws EOFException
    {
        if (mCursor + 1 > mBytes.length)
            throw new EOFException();
        int result = mBytes[mCursor];
        mCursor ++;
        return result;        
    }

    public short readShort()throws EOFException
    {
        if (mCursor + 2 > mBytes.length)
            throw new EOFException();        
        short result = (short)((mBytes[mCursor + 1] & 0xff) << 8); 
        result |= (short)(mBytes[mCursor] & 0xff);
        mCursor += 2;
        return result;
    }
    
    public int readUnsignedShort() throws EOFException
    {
        if (mCursor + 2 > mBytes.length)
            throw new EOFException();        
        int result = (int)((mBytes[mCursor + 1] & 0xff) << 8); 
        result |= (int)(mBytes[mCursor] & 0xff);
        mCursor += 2;
        return result;        
    }

    public int readInt()throws EOFException
    {
        if (mCursor + 4 > mBytes.length)
            throw new EOFException();        
        int result = (int)((mBytes[mCursor + 3] & 0xff) << 24);
        result |= (int)((mBytes[mCursor + 2] & 0xff) << 16);
        result |= (int)((mBytes[mCursor + 1] & 0xff) << 8);
        result |= (int)(mBytes[mCursor] & 0xff);
        mCursor += 4;
        return result;
    }

    public long writeLong()throws EOFException
    {
        if (mCursor + 8 > mBytes.length)
            throw new EOFException();        
        int half = (int)((mBytes[mCursor + 7] & 0xff) << 24);
        half |= (int)((mBytes[mCursor + 6] & 0xff) << 16);
        half |= (int)((mBytes[mCursor + 5] & 0xff) << 8);
        half |= (int)(mBytes[mCursor + 4] & 0xff);        
        long result = (long)((half & 0xffffffffL) << 32);
        
        half = (int)((mBytes[mCursor + 3] & 0xff) << 24);
        half |= (int)((mBytes[mCursor + 2] & 0xff) << 16);
        half |= (int)((mBytes[mCursor + 1] & 0xff) << 8);
        half |= (int)(mBytes[mCursor] & 0xff);
        result |= (long)(half & 0xffffffffL);
        
        mCursor += 8;
        return result;
    }

    public int readULeb128()throws EOFException
    {   
        int counter = mCursor;
        int result = 0;
        int shift = 0;
        while(true) 
        {
          byte b = mBytes[counter];
          result |= (int)((b & 0x7f) << shift);         
          if ((b & 0x80) == 0x00)
              break;
          if (counter >= mBytes.length)
              throw new EOFException();
          shift += 7;
          counter ++;
        }
        mCursor = counter + 1;
        return result;
    }

    public int readSLeb128()throws EOFException
    {
        int counter = mCursor;
        int result = 0;
        int shift = 0;
        int size = 31;
        byte end = 0;
        while(true) 
        {
            byte b = mBytes[counter];
            result |= (int)((b & 0x7f) << shift);
            shift += 7;
            if ((b & 0x80) == 0x00)
            {
                end = b;
                break;
            }
            if (counter >= mBytes.length)
                throw new EOFException();
            counter ++;
        }
        if ((shift < size) && (end & 0x40) == 0x40)
            result |= - (1 << shift);
        mCursor = counter + 1;
        return result;
    }

    public int read(byte[] bytes, int offset, int length)
    {
        int count = 0;
        while (count < length && (mCursor + count < mBytes.length))
        {
            bytes[offset + count] = mBytes[mCursor + count];
            count ++;
        }
        mCursor += count;
        return count;
    }

    public int read(byte[] bytes)
    {
        int count = 0;
        while (count < bytes.length && (mCursor + count < mBytes.length))
        {
            bytes[count] = mBytes[mCursor + count];
            count ++;
        }
        mCursor += count;
        return count;        
    }

    public int skipBytes(int n)
    {
        if (mCursor + n < mBytes.length)
        {
            mCursor += n;
            return n;
        }
        else
        {
            int count = mBytes.length - mCursor;
            mCursor = mBytes.length;
            return count;
        }
        
    }

}
